
#include "apdu_lib_dev_mgr.h"
#include "apdu_lib_common.h"
#include "apdu_lib_dev_opt.h"

#include "../apdu.core/apdu.h"

#include "../../mk_lib/mk_auto_ptr.h"
#include "../../mk_lib/mk_utility.h"

#include <stdlib.h>
#include <string.h>
#include "../apdu.algo/mac.h"

extern int	g_sw;

int app_transmit( HANDLE devHandle, unsigned char * command, int command_len,
				 unsigned char * response, int * response_len )
{
	if( 0 != get_dev_mgr()->transmit_command(devHandle,command, command_len, response, response_len))
	{
		g_sw = MCOS_SW_COMM_SEND;
		return 1;
	}

	return 0;
}

int app_set_label( HANDLE devHandle, char * label )
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_dev_mgr()->create_apdu_set_label(label);

	mk_auto_ptr<apdu> ap(newApdu);

	
	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}
	
	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}

int app_set_serial_number( HANDLE devHandle, char * serialNumber )
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_dev_mgr()->create_apdu_set_serial_num(serialNumber);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}

int app_get_dev_info( HANDLE devHandle, unsigned char * dev_info, int info_len )
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_dev_mgr()->create_apdu_get_dev_info();

	mk_auto_ptr<apdu> ap(newApdu);

	
	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = info_len;
	unsigned char * data = newApdu->get_response_data(&data_len);
	if(info_len < data_len)
	{
		return 3;
	}

	memcpy(dev_info, data, data_len);

	return 0;
}

int app_get_dev_short_info(HANDLE devHandle, unsigned char * dev_info, int info_len)
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_dev_mgr()->create_apdu_get_short_dev_info();

	mk_auto_ptr<apdu> ap(newApdu);


	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = info_len;
	unsigned char * data = newApdu->get_response_data(&data_len);
	if(info_len < data_len)
	{
		return 3;
	}

	memcpy(dev_info, data, data_len);

	return 0;
}

int app_gen_random( HANDLE devHandle, unsigned char * random, int len)
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_mgr()->create_apdu_gen_random(len, 0);

	mk_auto_ptr<apdu> ap(newApdu);
	
	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	int data_len = len;
	unsigned char * data = newApdu->get_response_data(&data_len);
	if(len < data_len)
	{
		return 3;
	}

	memcpy(random, data, data_len);

	if(g_sw != 0x9000)
	{
		return 2;
	}
	
	return 0;
}

int app_gen_remote_unlock_request(HANDLE devHandle, unsigned char * random, int len)
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_mgr()->create_apdu_gen_random(len, 1);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	int data_len = len;
	unsigned char * data = newApdu->get_response_data(&data_len);
	if(len < data_len)
	{
		return 3;
	}

	memcpy(random, data, data_len);

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}

int app_dev_auth( HANDLE devHandle, unsigned char algo, unsigned char * auth_data, int data_len )
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_dev_mgr()->create_apdu_dev_auth(algo, auth_data, data_len);

	mk_auto_ptr<apdu> ap(newApdu);

	
	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}

int app_change_dev_auth_key( HANDLE devHandle, int algo, unsigned char * secure_new_auth_key, int data_len)
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_dev_mgr()->create_apdu_change_dev_auth_key(algo,  secure_new_auth_key, data_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle, newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;

}

int app_change_dev_auth_key_ex( HANDLE devHandle, unsigned char * new_auth_key, int data_len)
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_dev_mgr()->create_apdu_change_dev_auth_key_ex(new_auth_key, data_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle, newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}


int app_dev_format( HANDLE devHandle, cosDevInfo * devInfo, unsigned char devAuthKey[32],
				   int retryTimes, int leftTimes, int isHighLevel)
{
	apdu * newApdu  =  NULL;
	newApdu = get_factory_mgr()->create_apdu_format(devInfo, devAuthKey,
					retryTimes, leftTimes, isHighLevel);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}

int app_dev_get_max_fscaps( HANDLE devHandle, int * fsCaps )
{
	apdu * newApdu  =  NULL;
	newApdu = get_factory_mgr()->create_apdu_get_fs_maxcap();

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * pData = newApdu->get_response_data(&data_len);
	
	if(data_len < 4)
	{
		return 3;
	}
	
	memcpy(fsCaps, pData, 4);
	mk_utility::reverse_bytes(fsCaps, 4);

	return 0;
}

int app_dev_get_raw_hwsn( HANDLE devHandle, unsigned char * sn, int * sn_len )
{
	apdu * newApdu  =  NULL;
	newApdu = get_factory_mgr()->create_apdu_get_hw_sn();

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * pData = newApdu->get_response_data(&data_len);

	if(*sn_len < data_len)
	{
		return 3;
	}
	
	*sn_len = data_len;

	memcpy(sn, pData, data_len);	

	return 0;
}

int app_dev_erase_firmware( HANDLE devHandle )
{
	char * password = "mCOSInit";
	apdu * newApdu  =  NULL;
	newApdu = get_factory_mgr()->create_apdu_back_to_bootloader(password);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}

int app_dev_get_dev_status( HANDLE devHandle, int * sts_format )
{
	apdu * newApdu  =  NULL;
	newApdu = get_factory_mgr()->create_apdu_get_fs_maxcap();

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * pData = newApdu->get_response_data(&data_len);

	if(data_len < 1)
	{
		return 3;
	}
	
	* sts_format = pData[0];

	return 0;
}

int app_write_oem_info( HANDLE devHandle, int offset, unsigned char * info, int info_len )
{
	apdu * newApdu  =  NULL;
	newApdu = get_factory_mgr()->create_apdu_write_oeminfo(offset, info, info_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * pData = newApdu->get_response_data(&data_len);

	if(data_len > info_len)
	{
		return 3;
	}

	memcpy(info, pData, data_len);
	return 0;
}

int app_read_oem_info( HANDLE devHandle, int offset, unsigned char * info, int * info_len )
{
	apdu * newApdu  =  NULL;
	newApdu = get_factory_mgr()->create_apdu_read_oeminfo(offset, *info_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * pData = newApdu->get_response_data(&data_len);
	if(data_len > *info_len)
	{
		return 3;
	}
	
	* info_len = data_len;

	memcpy(info, pData, data_len);
	return 0;
}

int app_sys_led_control( HANDLE devHandle, int state, int interval )
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_dev_mgr()->create_apdu_sys_led_control(state, interval);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}

int app_dev_lock_cos( HANDLE devHandle, unsigned char * password, int len)
{
	apdu * newApdu  =  NULL;
	newApdu = get_factory_mgr()->create_apdu_lock_cos(password, len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}




